using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace OverSizeImage
{
    public class GridAdorner : UserControl
    {
        Thumb leftThumb, topThumb, rightThumb, bottomThumb;
        Thumb leftTopThumb, rightTopThumb, rightBottomThumb, leftBottomThumb;

        Grid _grid;

        double InitSzie = 10.0;

        public double ScaleValue
        {
            get { return (double)GetValue(ScaleValueProperty); }
            set { SetValue(ScaleValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleValueProperty =
            DependencyProperty.Register("ScaleValue", typeof(double), typeof(GridAdorner), new PropertyMetadata(1.0, (sender, e) =>
            {
                var dp = sender as GridAdorner;
                if (dp == null) return;
                dp.ScaleChanged();
            }));

        public Brush ThumbBrush
        {
            get { return (Brush)GetValue(ThumbBrushProperty); }
            set { SetValue(ThumbBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ThumbBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ThumbBrushProperty =
            DependencyProperty.Register("ThumbBrush", typeof(Brush), typeof(GridAdorner), new PropertyMetadata(Brushes.White));





        private void ScaleChanged()
        {
            leftThumb.Width = InitSzie / ScaleValue;
            leftThumb.Height = InitSzie / ScaleValue;
            rightThumb.Width = InitSzie / ScaleValue;
            rightThumb.Height = InitSzie / ScaleValue;
            topThumb.Width = InitSzie / ScaleValue;
            topThumb.Height = InitSzie / ScaleValue;
            bottomThumb.Width = InitSzie / ScaleValue;
            bottomThumb.Height = InitSzie / ScaleValue;
            leftTopThumb.Width = InitSzie / ScaleValue;
            leftTopThumb.Height = InitSzie / ScaleValue;
            leftBottomThumb.Width = InitSzie / ScaleValue;
            leftBottomThumb.Height = InitSzie / ScaleValue;
            rightTopThumb.Width = InitSzie / ScaleValue;
            rightTopThumb.Height = InitSzie / ScaleValue;
            rightBottomThumb.Width = InitSzie / ScaleValue;
            rightBottomThumb.Height = InitSzie / ScaleValue;

            //rotateThumb.Width = InitSzie / ScaleValue;
            //rotateThumb.Height = InitSzie / ScaleValue;
        }

        public double X
        {
            get { return (double)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }

        // Using a DependencyProperty as the backing store for X.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty XProperty =
            DependencyProperty.Register("X", typeof(double), typeof(GridAdorner), new UIPropertyMetadata(0.0));

        public double Y
        {
            get { return (double)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Y.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty YProperty =
            DependencyProperty.Register("Y", typeof(double), typeof(GridAdorner), new UIPropertyMetadata(0.0));


        public double Angle
        {
            get { return (double)GetValue(AngleProperty); }
            set { SetValue(AngleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Angle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.Register("Angle", typeof(double), typeof(GridAdorner), new UIPropertyMetadata(0.0));



        public GridAdorner()
        {



            leftThumb = new Thumb();
            leftThumb.HorizontalAlignment = HorizontalAlignment.Left;
            leftThumb.VerticalAlignment = VerticalAlignment.Center;
            leftThumb.Cursor = Cursors.SizeWE;

            topThumb = new Thumb();
            topThumb.HorizontalAlignment = HorizontalAlignment.Center;
            topThumb.VerticalAlignment = VerticalAlignment.Top;
            topThumb.Cursor = Cursors.SizeNS;

            rightThumb = new Thumb();
            rightThumb.HorizontalAlignment = HorizontalAlignment.Right;
            rightThumb.VerticalAlignment = VerticalAlignment.Center;
            rightThumb.Cursor = Cursors.SizeWE;

            bottomThumb = new Thumb();
            bottomThumb.HorizontalAlignment = HorizontalAlignment.Center;
            bottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            bottomThumb.Cursor = Cursors.SizeNS;

            leftTopThumb = new Thumb();
            leftTopThumb.HorizontalAlignment = HorizontalAlignment.Left;
            leftTopThumb.VerticalAlignment = VerticalAlignment.Top;
            leftTopThumb.Cursor = Cursors.SizeNWSE;

            rightTopThumb = new Thumb();
            rightTopThumb.HorizontalAlignment = HorizontalAlignment.Right;
            rightTopThumb.VerticalAlignment = VerticalAlignment.Top;
            rightTopThumb.Cursor = Cursors.SizeNESW;

            rightBottomThumb = new Thumb();
            rightBottomThumb.HorizontalAlignment = HorizontalAlignment.Right;
            rightBottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            rightBottomThumb.Cursor = Cursors.SizeNWSE;

            leftBottomThumb = new Thumb();
            leftBottomThumb.HorizontalAlignment = HorizontalAlignment.Left;
            leftBottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            leftBottomThumb.Cursor = Cursors.SizeNESW;

            _grid = new Grid();

            

            _grid.Children.Add(leftThumb);
            InitThumb(leftThumb);
            _grid.Children.Add(topThumb);
            InitThumb(topThumb);
            _grid.Children.Add(rightThumb);
            InitThumb(rightThumb);
            _grid.Children.Add(bottomThumb);
            InitThumb(bottomThumb);
            _grid.Children.Add(leftTopThumb);
            InitThumb(leftTopThumb);
            _grid.Children.Add(rightTopThumb);
            InitThumb(rightTopThumb);
            _grid.Children.Add(rightBottomThumb);
            InitThumb(rightBottomThumb);
            _grid.Children.Add(leftBottomThumb);
            InitThumb(leftBottomThumb);
            
            AddVisualChild(_grid);
        }

        private void InitThumb(Thumb thumb)
        {
            thumb.Width = InitSzie;
            thumb.Height = InitSzie;
            thumb.Background = Brushes.Green;
            thumb.Template = new ControlTemplate(typeof(Thumb))
            {
                VisualTree = GetFactory(ThumbBrush)
            };
            thumb.DragDelta += Thumb_DragDelta;
        }

        protected override Visual GetVisualChild(int index)
        {
            return _grid;
        }

        protected override int VisualChildrenCount
        {
            get { return 1; }
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            _grid.Arrange(new Rect(new Point(-InitSzie / 2, -InitSzie / 2),
                new Size(finalSize.Width + InitSzie, finalSize.Height + InitSzie)));
            return finalSize;
        }

        private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            var thumb = sender as FrameworkElement;
            double width, height;
            if (thumb.HorizontalAlignment == HorizontalAlignment.Stretch && thumb.VerticalAlignment == VerticalAlignment.Stretch)
            {
                X += e.HorizontalChange;
                Y += e.VerticalChange;
                return;
            }

            if (thumb.HorizontalAlignment == HorizontalAlignment.Center && thumb.VerticalAlignment == VerticalAlignment.Center)
            {
                Point currentLocation = Mouse.GetPosition(this);
                Point knobCenter = new Point(this.ActualWidth / 2, this.ActualHeight / 2);

                double radians = Math.Atan((currentLocation.Y - knobCenter.Y) / (currentLocation.X - knobCenter.X));
                var angle = radians * 180 / Math.PI;
                Angle = angle % 360;
                return;
            }

            if (thumb.HorizontalAlignment == HorizontalAlignment.Left)
            {
                X += e.HorizontalChange;
                width = (double.IsNaN(Width) ? ActualWidth : Width) - e.HorizontalChange;
            }
            else
            {
                width = (double.IsNaN(Width) ? ActualWidth : Width) + e.HorizontalChange;
            }

            if (thumb.VerticalAlignment == VerticalAlignment.Top)
            {
                Y += e.VerticalChange;
                height = (double.IsNaN(Height) ? ActualHeight : Height) - e.VerticalChange;
            }
            else
            {
                height = (double.IsNaN(Height) ? ActualHeight : Height) + e.VerticalChange;
            }

            if (thumb.HorizontalAlignment != HorizontalAlignment.Center)
            {
                if (width >= 0)
                {
                    Width = width;
                }
            }
            if (thumb.VerticalAlignment != VerticalAlignment.Center)
            {
                if (height >= 0)
                {
                    Height = height;
                }
            }
        }

        private FrameworkElementFactory GetFactory(Brush back)
        {
            var fef = new FrameworkElementFactory(typeof(Ellipse));
            fef.SetValue(Ellipse.FillProperty, back);
            return fef;
        }

        private FrameworkElementFactory GetWholeFactory(Brush back)
        {
            var fef = new FrameworkElementFactory(typeof(Rectangle));
            fef.SetValue(Ellipse.FillProperty, back);
            return fef;
        }
    }
}
